package com.linkai.JUC._04_unsafecollection;


import java.util.*;

/**
 * @Description:  1. iterator 遍历 map，有2种方式
 *                   https://zhuanlan.zhihu.com/p/348478570
 *                  （1）使用 map.keySet().iterator;
 *                  （2）使用 map.entrySet().iterator;
 *                      推荐使用第2种方式遍历，因为keySet中只有key，而entrySet中既有key也有value，
 *                      不再需要从map里面拿取value
 *                 2. Iterator 介绍
 *                   迭代器也就是将集合的数据放到一个容器中并排成一排，iterator有一个游标，最初的时候，
 *                   游标在第一个元素前面，调用Iterator.next()是将游标往后移一位，
 *                   Iterator.hasNext()是判断游标后面还没有可以迭代的元素。
 *
 *                 3. 关于 fail-fast（快速失败) 机制和 fail-safe（安全失败）机制
 *                   https://www.cnblogs.com/u013533289/p/11637885.html
 *                  （1）普通集合都是基于 fail-fast 机制的，即遍历的时候在直接在原集合上进行操作，所以此时增加或者删除元素，
 *                  会抛出异常。
 *                  （2）而JUC包下的例如 CopyOnWriteArrayList，ConcurrentHashMap 是基于 fail-safe 机制的，
 *                  遍历的时候是先进行一次拷贝，遍历操作是在拷贝的副本上进行的，所以即使此时增加或者删除元素，
 *                  也不会抛出异常，但是遍历的时候新插入的元素是遍历不到的。
 *
 * @Author: 林凯
 * @Date: 2021/11/20 9:19
 */
public class ForeachTest {

    // 1. 测试 iterator 遍历 map
    public static void testMapIterator() {
        HashMap<String, String> hashMap = new HashMap<>();
        hashMap.put("k1", "v1");
        hashMap.put("k2", "v2");
        hashMap.put("k3", "v3");
        // keySet() 里面只包含了 key
        Set<String> sets = hashMap.keySet();
        // entrySet() 里面既包含了key，也包含了value
        Set<Map.Entry<String, String>> entries = hashMap.entrySet();
        // （1）使用 keyset 遍历；用foreach或者 iterator都可以
        System.out.println("foreach遍历----keySet");
        for (String key:hashMap.keySet()
             ) {
            System.out.println(key);
            System.out.println(hashMap.get(key));
        }
        System.out.println("iterator遍历-----keySet");
        Iterator iteratorKeySet = sets.iterator();
        while (iteratorKeySet.hasNext()) {
            String next = (String) iteratorKeySet.next();
            System.out.println(next);
            System.out.println(hashMap.get(next));
        }
        //（2）使用 entrySet 遍历；同样用 foreach 和 iterator 都可以
        System.out.println("---------");
        System.out.println("foreach遍历entrySet------");
        for (Map.Entry<String, String> entry:entries
             ) {
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }

        System.out.println("iterator遍历entrySet()-----");
        Iterator<Map.Entry<String, String>> iterator = hashMap.entrySet().iterator();
        while (iterator.hasNext()) {
            // 要将这个 next 变量先保存起来，否则每执行一次 next，iterator的指针就往后移动一位。
            Map.Entry<String, String> next = iterator.next();
            System.out.println(next.getKey());
            System.out.println(next.getValue());
        }
    }

    // 2. 测试 iterator 遍历 list
    public static void testArrayListIterator() {
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("s1");
        arrayList.add("s2");
        arrayList.add("s3");
        arrayList.add("s4");
        Iterator<String> iterator = arrayList.iterator();
        int i = 0;
        while (iterator.hasNext()) {
            if (i == 1) {
                arrayList.remove(1);        // ConcurrentModificationException
            }
            System.out.println(iterator.next());
            // ArrayList基于 fail-fast 机制，遍历过程中如果修改，则会抛出异常
            // 方法1. 修改的话剧尽量使用 iterator.remove() 方法
            // 方法2：使用 fail-safe 机制，即使用 JUC 下的 CopyOnWriterArrayList 来代替。
//            iterator.remove();
            i++;
        }
        System.out.println("----");
        System.out.println(arrayList);
    }

    public static void main(String[] args) {
//        testMapIterator();
        testArrayListIterator();
    }
}
